import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';

let resultPanel: vscode.WebviewPanel | undefined;

interface LLMMessage {
    role: string;
    content: string;
}

interface LLMChoice {
    message: LLMMessage;
    index: number;
    finish_reason: string;
}

interface LLMResponse {
    id: string;
    object: string;
    created: number;
    choices: LLMChoice[];
    model: string;
}

export function activate(context: vscode.ExtensionContext) {
    // Register commands
    context.subscriptions.push(
        vscode.commands.registerCommand('zzl-code-helper.configure', () => {
            vscode.commands.executeCommand('workbench.action.openSettings', 'zzlCodeHelper');
        }),

        vscode.commands.registerCommand('zzl-code-helper.analyzeFunctionality', async () => {
            const editor = vscode.window.activeTextEditor;
            if (editor) {
                const text = editor.document.getText(editor.selection);
                await analyze(text, 'contentPrompt');
            }
        }),

        vscode.commands.registerCommand('zzl-code-helper.analyzeSyntax', async () => {
            const editor = vscode.window.activeTextEditor;
            if (editor) {
                const text = editor.document.getText(editor.selection);
                await analyze(text, 'syntaxPrompt');
            }
        }),

        vscode.commands.registerCommand('zzl-code-helper.analyzeModule', async (uri: vscode.Uri) => {
            const folderContent = await getFolderContent(uri.fsPath);
            await analyze(folderContent, 'modulePrompt');
        })
    );
}

async function getFolderContent(folderPath: string): Promise<string> {
    let directoryStructure = 'Directory structure:\n';
    let fileContents = 'All File contents:\n';
    
    function buildTree(dir: string, prefix: string = ''): void {
        const items = fs.readdirSync(dir);
        
        for (const item of items) {
            const fullPath = path.join(dir, item);
            const stats = fs.statSync(fullPath);
            
            if (stats.isDirectory()) {
                directoryStructure += `${prefix}└── ${item}/\n`;
                buildTree(fullPath, `${prefix}    `);
            } else {
                directoryStructure += `${prefix}└── ${item}\n`;
                // Add file content to separate section
                const fileContent = fs.readFileSync(fullPath, 'utf-8');
                fileContents += `\nFile: ${fullPath}\nFile Content:\n${fileContent}\n`;
            }
        }
    }
    
    buildTree(folderPath);
    return directoryStructure + '\n==================\n' + fileContents;
}

async function analyze(content: string, promptType: string) {
    // 在发送请求前先创建和显示侧边栏
    if (!resultPanel) {
        resultPanel = vscode.window.createWebviewPanel(
            'zzlAnalysis',
            'ZZL Analysis Result',
            vscode.ViewColumn.Three,
            { 
                enableScripts: true,
                retainContextWhenHidden: true,
            }
        );
        
        initializeResultPanel();
    }
    
    // 显示加载状态
    resultPanel.webview.html = getWebviewContent('', true); // 传入 true 表示显示加载状态

    const config = vscode.workspace.getConfiguration('zzlCodeHelper');
    let prompt = config.get<string>(promptType) || '';
    
    // Set default prompts if not configured
    if (!prompt) {
        switch (promptType) {
            case 'modulePrompt':
                prompt = `
你是专业软件工程师，分析当前项目详细执行流程。标注相关代码、并且必须标注代码文件路径和引用代码的开始行和结束行，以便我能在源码中定位阅读。注意答案中引用的代码必须在当前项目中存在. 如果需要引用代码文件中的代码段，在代码块的首行，按照以下方式支出代码段所在的文件和代码开始和结束行：
###代码标注格式举例：
以下是关键代码
\`\`\`java
// /home/GlobalScheduler.java[100:110]
@Override
public boolean yieldIfNeeded(PreparedSQLStatement current) {
    // 检查是否有更高优先级命令
    nextBestCommand = getNextBestCommand(current.getSession(), priority, false);
    if (nextBestCommand != null) {
        current.setPriority(priority + 1);
        return true;
    }
    return false;
}
\`\`\`
###以上例子中/home/GlobalScheduler.java[100:110]，表示代码块在/home/GlobalScheduler.java这个文件的100行到110行。
###其他要求：
    1. 使用中文回答。
    2. 输出代码块时，必须按照前面的描述输出代码块格式。
    3. 代码块中必须包含文件路径、开始行号，结束行号。
    4. 代码的开始行号和结束行号必须和原始代码文件的代码正确对应。
###项目结构及代码如下：\n
					`;
                break;
            case 'contentPrompt':
                prompt = '请分析这段代码的功能，解释它的主要作用和实现逻辑。\n分析包括：\n1. 代码的主要功能\n2. 实现思路\n3. 关键算法或方法\n4. 可能的使用场景，代码如下：\n';
                break;
            case 'syntaxPrompt':
                prompt = '请解释这段代码的语法结构，详细说明使用的语言特性。\n分析包括：\n1. 使用的语言特性\n2. 语法结构解释\n3. 关键语句说明\n4. 编程范式分析，代码如下：\n';
                break;
        }
    }

    content = prompt + "\n" + content;
    try {
        const response = await fetch(config.get('llmUrl') || '', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${config.get('apiKey')}`
            },
            body: JSON.stringify({
                model: config.get('modelName'),
                messages: [
                    { role: 'system', 'content': '你是多才多艺，乐于助人的助手，帮助用户分析代码.' },
                    { role: 'user', 'content': content }
                ]
            })
        });

        const result = await response.json() as LLMResponse;
        if (!result.choices?.[0]?.message?.content) {
            throw new Error('Invalid response format from LLM API');
        }
        
        // 更新结果内容，传入 false 表示隐藏加载状态
        resultPanel.webview.html = getWebviewContent(result.choices[0].message.content, false);
    } catch (error) {
        vscode.window.showErrorMessage(`Analysis failed: ${error}`);
        // 显示错误状态，同时隐藏加载动画
        resultPanel.webview.html = getWebviewContent(`Error: ${error}`, false);
    }
}

// 将事件处理逻辑抽取为单独的函数
function initializeResultPanel() {
    if (!resultPanel) return;

    resultPanel.webview.onDidReceiveMessage(async message => {
        try {
            if (message.command === 'openFile') {
                const existingEditor = vscode.window.visibleTextEditors.find(
                    editor => editor.document.uri.fsPath === message.file
                );

                let editor;
                if (existingEditor) {
                    editor = existingEditor;
                } else {
                    const document = await vscode.workspace.openTextDocument(message.file);
                    editor = await vscode.window.showTextDocument(document, {
                        viewColumn: vscode.ViewColumn.One,
                        preserveFocus: false,
                        preview: false
                    });
                }

                const range = new vscode.Range(
                    message.startLine - 1,
                    0,
                    message.endLine - 1,
                    0
                );
                editor.revealRange(range);
                editor.selection = new vscode.Selection(range.start, range.start);
            }
        } catch (error) {
            vscode.window.showErrorMessage(`Failed to open file: ${error}`);
        }
    });
    
    resultPanel.onDidDispose(() => {
        resultPanel = undefined;
    });
}

// 修改 getWebviewContent 函数签名，添加 isLoading 参数
function getWebviewContent(markdown: string, isLoading: boolean = false) {
    const escapedContent = markdown
        .replace(/\\/g, '\\\\')
        .replace(/`/g, '\\`')
        .replace(/\$/g, '\\$');

    return `
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <script src="https://cdn.jsdelivr.net/npm/marked@4.0.0/marked.min.js"></script>
            <style>
                body { padding: 15px; }
                pre { background-color: #f0f0f0; padding: 10px; cursor: pointer; }
                pre:hover { background-color: #e0e0e0; }
                .error { color: red; padding: 10px; border: 1px solid red; }
                
                /* 加载指示器样式 */
                .loading {
                    position: fixed;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    display: none;
                }
                .loading.active {
                    display: block;
                }
                .spinner {
                    width: 40px;
                    height: 40px;
                    border: 4px solid #f3f3f3;
                    border-top: 4px solid #3498db;
                    border-radius: 50%;
                    animation: spin 1s linear infinite;
                }
                @keyframes spin {
                    0% { transform: rotate(0deg); }
                    100% { transform: rotate(360deg); }
                }
                #content.loading {
                    opacity: 0.5;
                }
            </style>
        </head>
        <body>
            <div class="loading ${isLoading ? 'active' : ''}" id="loadingIndicator">
                <div class="spinner"></div>
                <div style="margin-top: 10px; text-align: center;">正在分析中...</div>
            </div>
            <div id="content" ${isLoading ? 'style="display: none;"' : ''}></div>
            <div id="error" style="display:none" class="error"></div>
            <script>
                const vscode = acquireVsCodeApi();
                let previousState = vscode.getState() || { scrollPosition: 0 };
                
                window.addEventListener('scroll', () => {
                    const position = document.documentElement.scrollTop || document.body.scrollTop;
                    previousState.scrollPosition = position;
                    vscode.setState(previousState);
                });

                (function() {
                    try {
                        const markdownContent = \`${escapedContent}\`;
                        function parseCodeInfo(inputStr) {
                            const firstLine = inputStr.split('\\n')[0].trim();
                            const fullPath = firstLine.split(' ')[1];
                            const [filepath, lineSection] = fullPath.split('[');
                            const lineParts = lineSection.replace(']', '').split(':');
                            const lineinfo = lineParts.map(Number);

                            return {
                                filepath,
                                lineinfo
                            };
                        }

                        function initMarked() {
                            if (typeof marked === 'undefined') {
                                setTimeout(initMarked, 100);
                                return;
                            }

                            try {
                                const renderer = new marked.Renderer();
                                renderer.code = function(code, language) {
                                    if (!code) {
                                        return \`<pre><code class="\${language || ''}">\${code}</code></pre>\`;
                                    }
                                    let parseResult;
                                    try {
                                        parseResult = parseCodeInfo(code);
                                    } catch (error) {
                                        return \`<pre><code class="\${language || ''}">\${code}</code></pre>\`;
                                    }
                                    if (parseResult) {
                                        const filepath = parseResult.filepath;
                                        const [startLine, endLine] = parseResult.lineinfo;
                                        const codeId = 'code-' + Math.random().toString(36).substr(2, 9);
                                        return \`<pre id="\${codeId}" data-file="\${filepath}" data-start="\${startLine}" data-end="\${endLine}">\${code}</pre>\`;
                                    }
                                    return \`<pre><code class="\${language || ''}">\${code}</code></pre>\`;
                                };

                                marked.setOptions({ renderer });
                                document.getElementById('content').innerHTML = marked.parse(markdownContent);
                                
                                if (previousState.scrollPosition) {
                                    window.scrollTo(0, previousState.scrollPosition);
                                }

                                document.querySelectorAll('pre[data-file]').forEach(pre => {
                                    pre.addEventListener('click', () => {
                                        vscode.postMessage({
                                            command: 'openFile',
                                            file: pre.dataset.file,
                                            startLine: parseInt(pre.dataset.start),
                                            endLine: parseInt(pre.dataset.end)
                                        });
                                    });
                                });
                            } catch (error) {
                                document.getElementById('error').style.display = 'block';
                                document.getElementById('error').textContent = 'Error processing markdown: ' + error.message;
                            }
                        }

                        initMarked();
                    } catch (error) {
                        document.getElementById('error').style.display = 'block';
                        document.getElementById('error').textContent = 'Script initialization error: ' + error.message;
                        document.getElementById('content').textContent = markdownContent;
                    }
                })();
            </script>
        </body>
        </html>
    `;
}

export function deactivate() {}
